﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Remoting;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Threading;
using GurLoader;
using GurLoader.Service;
using Moq;
using NUnit.Framework;

namespace GurLoaderWPF.Test.Service
{
    [TestFixture]
    public class CommandProgressExTests
    {
        [Test]
        public void CreateInstanceTest()
        {
            Command command = Command.SendAlbum;
            int progress = 32;
            string status = "In progress";
            List<CommandProgress> children = new List<CommandProgress>();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();

            var instance = new CommandProgressEx(command, progress, status, children, mockDispatcher.Object);

            Assert.IsNotNull(instance);

            Assert.AreEqual(command, instance.Command);
            Assert.AreEqual(progress, instance.ProgressPercentage);
            Assert.AreEqual(status, instance.Status);
            CollectionAssert.AreEquivalent(children, instance.Children);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CreateInstanceNullDispatcherTest()
        {
            Command command = Command.SendAlbum;
            int progress = 32;
            string status = "In progress";
            List<CommandProgress> children = new List<CommandProgress>();

            var instance = new CommandProgressEx(command, progress, status, children, null);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CreateInstanceNullChildrenTest()
        {
            Command command = Command.SendAlbum;
            int progress = 32;
            string status = "In progress";
            List<CommandProgress> children = null;
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();

            var instance = new CommandProgressEx(command, progress, status, children, mockDispatcher.Object);
        }

        [Test]
        public void AddChildTest()
        {
            Command command = Command.SendAlbum;
            int progress = 32;
            string status = "In progress";
            List<CommandProgress> children = new List<CommandProgress>();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();

            mockDispatcher.Setup(
                x => x.Invoke(It.IsAny<Delegate>(), It.IsAny<DispatcherPriority>(), It.IsAny<object[]>()))
                .Callback(
                    new Action<Delegate, DispatcherPriority, object[]>((d, dp, args) =>
                    {
                        d.GetMethodInfo().Invoke(d.Target, args);
                    }));

            var instance = new CommandProgressEx(command, progress, status, children, mockDispatcher.Object);

            Assert.IsNotNull(instance);

            CommandProgress child = new CommandProgress(command, progress, status);

            CollectionAssert.IsEmpty( instance.Children );
            
            instance.AddChild(child);

            CollectionAssert.Contains(instance.Children, child);
            Assert.AreEqual(1, instance.Children.Count);

            mockDispatcher.Verify(
                x => x.Invoke(
                    It.IsAny<Delegate>(),
                    It.IsAny<DispatcherPriority>(),
                    It.IsAny<object[]>()), Times.Once);
        }

        [Test]
        public void AddChildNullTest()
        {
            Command command = Command.SendAlbum;
            int progress = 32;
            string status = "In progress";
            List<CommandProgress> children = new List<CommandProgress>();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();

            mockDispatcher.Setup(
                x => x.Invoke(It.IsAny<Delegate>(), It.IsAny<DispatcherPriority>(), It.IsAny<object[]>()))
                .Callback(
                    new Action<Delegate, DispatcherPriority, object[]>((d, dp, args) =>
                    {
                        d.GetMethodInfo().Invoke(d.Target, args);
                    }));

            var instance = new CommandProgressEx(command, progress, status, children, mockDispatcher.Object);

            Assert.IsNotNull(instance);

            CommandProgress child = null;

            CollectionAssert.IsEmpty(instance.Children);

            instance.AddChild(child);

            CollectionAssert.IsEmpty(instance.Children);

            mockDispatcher.Verify(
                x => x.Invoke(
                    It.IsAny<Delegate>(),
                    It.IsAny<DispatcherPriority>(),
                    It.IsAny<object[]>()), Times.Never);
        }

        [Test]
        public void RemoveChildTest()
        {
            Command command = Command.SendAlbum;
            int progress = 32;
            string status = "In progress";
            List<CommandProgress> children = new List<CommandProgress>();
            CommandProgress child = new CommandProgress(command, progress, status);

            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();

            mockDispatcher.Setup(
                x => x.Invoke(It.IsAny<Delegate>(), It.IsAny<DispatcherPriority>(), It.IsAny<object[]>()))
                .Callback(
                    new Action<Delegate, DispatcherPriority, object[]>((d, dp, args) =>
                    {
                        d.GetMethodInfo().Invoke(d.Target, args);
                    }));

            children.Add(child);

            var instance = new CommandProgressEx(command, progress, status, children, mockDispatcher.Object);

            Assert.IsNotNull(instance);
            CollectionAssert.Contains(instance.Children, child);
            Assert.AreEqual(1, instance.Children.Count);

            instance.RemoveChild(child);

            CollectionAssert.IsEmpty(instance.Children);

            mockDispatcher.Verify(
                x => x.Invoke(
                    It.IsAny<Delegate>(),
                    It.IsAny<DispatcherPriority>(),
                    It.IsAny<object[]>()), Times.Once);
        }

        [Test]
        public void RemoveChildNullTest()
        {
            Command command = Command.SendAlbum;
            int progress = 32;
            string status = "In progress";
            List<CommandProgress> children = new List<CommandProgress>();
            CommandProgress child = new CommandProgress(command, progress, status);

            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();

            mockDispatcher.Setup(
                x => x.Invoke(It.IsAny<Delegate>(), It.IsAny<DispatcherPriority>(), It.IsAny<object[]>()))
                .Callback(
                    new Action<Delegate, DispatcherPriority, object[]>((d, dp, args) =>
                    {
                        d.GetMethodInfo().Invoke(d.Target, args);
                    }));

            children.Add(child);

            var instance = new CommandProgressEx(command, progress, status, children, mockDispatcher.Object);

            Assert.IsNotNull(instance);
            CollectionAssert.Contains(instance.Children, child);
            Assert.AreEqual(1, instance.Children.Count);

            instance.RemoveChild(null);

            CollectionAssert.Contains(instance.Children, child);
            Assert.AreEqual(1, instance.Children.Count);

            mockDispatcher.Verify(
                x => x.Invoke(
                    It.IsAny<Delegate>(),
                    It.IsAny<DispatcherPriority>(),
                    It.IsAny<object[]>()), Times.Never);
        }
    }
}
